home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fs / fsSysCall.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  51.3 KB  |  1,923 lines

  1. /* 
  2.  * fsSysCall.c --
  3.  *
  4.  *    These are the system call stubs that get called from the
  5.  *    system call trap handler.  These routines make sure that
  6.  *    their arguments are addressable and then call the workhorse
  7.  *    routines to do the actual work.
  8.  *
  9.  * Copyright 1987 Regents of the University of California
  10.  * All rights reserved.
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fs/fsSysCall.c,v 9.12 92/04/17 13:53:55 jhh Exp $ SPRITE (Berkeley)";
  22. #endif not lint
  23.  
  24.  
  25. #include <sprite.h>
  26.  
  27. #include <fs.h>
  28. #include <fsutil.h>
  29. #include <fsNameOps.h>
  30. #include <fsio.h>
  31. #include <fslcl.h>
  32. #include <fsdm.h>
  33. #include <vm.h>
  34. #include <proc.h>
  35.  
  36.  
  37. /*
  38.  *----------------------------------------------------------------------
  39.  *
  40.  * Fs_AttachDiskStub --
  41.  *
  42.  *    Stub for the Fs_AttachDisk system call.  This gets ahold of
  43.  *    the filename arguments, opens the disk to be attached, and
  44.  *    calls Fsdm_AttachDisk to do the work.
  45.  *
  46.  * Results:
  47.  *    SUCCESS, or an error code from finding junk on the disk.
  48.  *
  49.  * Side effects:
  50.  *    Call Fs_AttachDisk or Fs_DetachDisk.
  51.  *
  52.  *----------------------------------------------------------------------
  53.  */
  54.  
  55. ReturnStatus
  56. Fs_AttachDiskStub(userDeviceName, userLocalName, flags)
  57.     char *userDeviceName;/* Name of raw disk device file to attach */
  58.     char *userLocalName;/* Local directory name where disk is attached */
  59.     int flags;        /* FS_ATTACH_READ_ONLY, FS_DETATCH, FS_ATTACH_LOCAL */
  60. {
  61.     ReturnStatus status;
  62.     int useFlags;        /* Flags for the Fs_Open call */
  63.     Fs_Stream *streamPtr;    /* Stream from the Fs_Open call */
  64.     char *deviceName;        /* Kernel resident pathname storage */
  65.     char *localName;        /* Kernel resident pathname storage */
  66.     int    localNameLength;
  67.     int    deviceNameLength;
  68.  
  69.     if (userLocalName != (char *)NIL && userLocalName != (char *)0) {
  70.     localName = (char *)malloc(FS_MAX_PATH_NAME_LENGTH);
  71.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, userLocalName, localName,
  72.                &localNameLength) != SUCCESS) {
  73.         free(localName);
  74.         return(SYS_ARG_NOACCESS);
  75.     }
  76.     } else {
  77.     localName = (char *)NIL;
  78.     }
  79.     if (userDeviceName != (char *)NIL && userDeviceName != (char *)0) {
  80.     deviceName = (char *)malloc(FS_MAX_PATH_NAME_LENGTH);
  81.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, userDeviceName, deviceName,
  82.                &deviceNameLength) != SUCCESS) {
  83.         if (localName != (char *)NIL) {
  84.         free(localName);
  85.         }
  86.         free(deviceName);
  87.         return(SYS_ARG_NOACCESS);
  88.     }
  89.     } else {
  90.     deviceName = (char *)NIL;
  91.     }
  92.     if (flags & FS_DETACH) {
  93.     /*
  94.      * Flush data associated with the domain and remove the domain
  95.      * from the prefix table.
  96.      */
  97.     status = Fsdm_DetachDisk(localName);
  98.     } else {
  99.     /*
  100.      * Attach a local domain into the prefix table.
  101.      */
  102.     if (deviceName == (char *)NIL ||
  103.         localName == (char *)NIL) {
  104.         status = FS_INVALID_ARG;
  105.     } else {
  106.         if (flags & FS_ATTACH_READ_ONLY) {
  107.         useFlags = FS_READ;
  108.         } else {
  109.         useFlags = FS_READ|FS_WRITE;
  110.         }
  111.         status = Fs_Open(deviceName, useFlags, FS_DEVICE, 0, &streamPtr);
  112.         if (status == SUCCESS) {
  113.         status = Fsdm_AttachDiskByHandle(streamPtr->ioHandlePtr, 
  114.                          localName, flags);
  115.         }
  116.     }
  117.     }
  118.     if (deviceName != (char *)NIL) {
  119.     free(deviceName);
  120.     }
  121.     if (localName != (char *)NIL) {
  122.     free(localName);
  123.     }
  124.     return(status);
  125. }
  126.  
  127. /*
  128.  *----------------------------------------------------------------------
  129.  *
  130.  * Fs_OpenStub --
  131.  *
  132.  *      This is the stub for the Fs_Open system call.  This routine makes
  133.  *    its arguments accessible, then sets up a Stream ID for the Fs_Stream
  134.  *      object returned by (the internal) Fs_Open.  Stream Id's get
  135.  *      passed to read and write calls and identify the stream to the
  136.  *      system.  If FS_CREATE is one of the usage flags then the third
  137.  *      argument, permissions, specifies the base permissions for the
  138.  *      newly created file.
  139.  *
  140.  * Results:
  141.  *    An error code or SUCCESS if successful.
  142.  *
  143.  * Side effects:
  144.  *    The last argument is an out parameter and gets filled in with
  145.  *    the stream id.  
  146.  *
  147.  *----------------------------------------------------------------------
  148.  */
  149.  
  150. ReturnStatus
  151. Fs_OpenStub(pathName, usageFlags, permissions, streamIDPtr)
  152.     char *pathName;        /* The name of the file to open */
  153.     int usageFlags;        /* FS_READ, FS_WRITE, FS_CREATE, FS_TRUNC */
  154.     int permissions;        /* Permission mask to use on creation */
  155.     int *streamIDPtr;        /* This is the user's handle on the open
  156.                  * file used in later filesystem requests */
  157. {
  158.     int             streamID;
  159.     Fs_Stream         *streamPtr;
  160.     ReturnStatus     status;
  161.     int            pathNameLength;
  162.     char        newName[FS_MAX_PATH_NAME_LENGTH];
  163.  
  164.     /*
  165.      * Copy the name in from user space to the kernel stack.
  166.      */
  167.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  168.                &pathNameLength) != SUCCESS) {
  169.     return(SYS_ARG_NOACCESS);
  170.     }
  171.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  172.     return(FS_INVALID_ARG);
  173.     }
  174.  
  175.     /*
  176.      * Open the file and get a stream descriptor for it.
  177.      */
  178.     usageFlags &= ~FS_KERNEL_FLAGS;
  179.     usageFlags |= (FS_USER | FS_FOLLOW);
  180.  
  181.     status = Fs_Open(newName, usageFlags, FS_FILE,
  182.              permissions & 0777, &streamPtr);
  183.     
  184.     if (status != SUCCESS) {
  185.     return(status);
  186.     }
  187.  
  188.     /*
  189.      * Save a pointer to the descriptor in a list kept in the proc table.
  190.      * Its index in the list is the "Stream ID".
  191.      */
  192.  
  193.     status = Fs_GetStreamID(streamPtr, &streamID);
  194.     if (status != SUCCESS) {
  195.     (void) Fs_Close(streamPtr);
  196.     return(status);
  197.     }
  198.  
  199.     if (Vm_CopyOut(sizeof(int), (Address) &streamID, 
  200.            (Address) streamIDPtr) == SUCCESS) {
  201.     return(SUCCESS);
  202.     } 
  203.     status = SYS_ARG_NOACCESS;
  204.     (void) Fs_UserClose(streamID);    /* This clears the streamID, too */
  205.     return(status);
  206. }
  207.  
  208.  
  209. /*
  210.  *----------------------------------------------------------------------
  211.  *
  212.  * Fs_UserClose --
  213.  *
  214.  *    System call to release a stream Id.  Calls then internal Fs_Close
  215.  *    routine.
  216.  *
  217.  * Results:
  218.  *    An return status.
  219.  *
  220.  * Side effects:
  221.  *    The streamID becomes invalid (until it gets reassigned by
  222.  *    another Fs_Open call).
  223.  *
  224.  *----------------------------------------------------------------------
  225.  */
  226.  
  227. ReturnStatus
  228. Fs_UserClose(streamID)
  229.     int streamID;
  230. {
  231.     ReturnStatus    status;
  232.     Fs_Stream         *streamPtr;    /* Stream pointer from the process's
  233.                       * list of open streams */
  234.     Proc_ControlBlock    *procPtr;    /* This process's control block */
  235.     
  236.     /*
  237.      * Map from the streamID to a streamPtr.
  238.      */
  239.  
  240.     procPtr = Proc_GetEffectiveProc();
  241.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  242.     if (status != SUCCESS) {
  243.     /*
  244.      * Fudge the return status.  A close() can only return EBADF or
  245.      * EINTR, so return something that maps to EBADF even if it
  246.      * doesn't make sense here.  Sprite system calls are going
  247.      * away soon anyway.
  248.      */
  249.     if (status != GEN_EINTR) {
  250.         return(FS_NEW_ID_TOO_BIG);
  251.     }
  252.     return(status);
  253.     }
  254.  
  255.     /*
  256.      * Look after any shared memory associated with the file.
  257.      */
  258.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  259.     Vm_CleanupSharedFile(procPtr,streamPtr);
  260.     }
  261.  
  262.     /*
  263.      * Clear the user-level streamID and then close the underlying stream.
  264.      */
  265.  
  266.     Fs_ClearStreamID(streamID, procPtr);
  267.     status = Fs_Close(streamPtr);
  268.  
  269.     return(status);
  270. }
  271.  
  272.  
  273. /*
  274.  *----------------------------------------------------------------------
  275.  *
  276.  * Fs_ReadStub --
  277.  *
  278.  *      The stub for the Fs_Read system call.  Calls Fs_UserRead to do the
  279.  *    work, then copies out the argument to the user's address space.
  280.  *
  281.  * Results:
  282.  *    An return status.
  283.  *
  284.  * Side effects:
  285.  *    The amountReadPtr is updated to reflect the amount actually read.
  286.  *
  287.  *----------------------------------------------------------------------
  288.  */
  289.  
  290. ReturnStatus
  291. Fs_ReadStub(streamID, amountRead, buffer, amountReadPtr)
  292.     int        streamID;    /* The user's index into its open file list */
  293.     int        amountRead;    /* The amount of bytes to read */
  294.     Address    buffer;        /* The storage place for the read */
  295.     int        *amountReadPtr;    /* The amount of bytes actually read */
  296. {
  297.     register ReturnStatus    status;
  298.     Fs_Stream        *streamPtr;    /* The stream to read from */
  299.     Proc_ControlBlock     *procPtr;    /* This process's control block */
  300.  
  301.     /*
  302.      * (Begin inlined called to Fs_UserRead.)
  303.      */
  304.     /*
  305.      * Map from stream ID to file pointer and do the read.
  306.      * If the process is not remote, Fs_Read takes care of making
  307.      * the read buffer accessible.
  308.      */
  309.  
  310.     procPtr = Proc_GetEffectiveProc();
  311.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  312.     if (status == SUCCESS) {
  313.     status = Fs_Read(streamPtr, buffer, streamPtr->offset, &amountRead);
  314.     } else {
  315.     amountRead = 0;
  316.     }
  317.     /*
  318.      * (End Fs_UserRead.)
  319.      */
  320.  
  321.     if (Vm_CopyOut(sizeof(int), (Address) &amountRead, 
  322.            (Address) amountReadPtr) != SUCCESS) {
  323.     status = SYS_ARG_NOACCESS;
  324.     }
  325.     return(status);
  326. }
  327.  
  328.  
  329. /*
  330.  *----------------------------------------------------------------------
  331.  *
  332.  * Fs_UserRead --
  333.  *
  334.  *      The Fs_Read system call.  Read from the file indicated by the
  335.  *      stream id into the buffer.  bufSize indicates how much
  336.  *      data to read, and amountReadPtr is an output parameter that
  337.  *      indicates how much data was read.  A length of zero means
  338.  *      end-of-file.
  339.  *
  340.  * Results:
  341.  *    A return status.
  342.  *
  343.  * Side effects:
  344.  *    The amountReadPtr is updated to reflect the amount actually read.
  345.  *
  346.  *----------------------------------------------------------------------
  347.  */
  348.  
  349. ReturnStatus
  350. Fs_UserRead(streamID, amountRead, buffer, amountReadPtr)
  351.     int        streamID;    /* The user's index into its open file list */
  352.     int        amountRead;    /* The amount of bytes to read */
  353.     Address    buffer;        /* The storage place for the read */
  354.     int        *amountReadPtr;    /* The amount of bytes actually read */
  355. {
  356.     register ReturnStatus    status;
  357.     Fs_Stream        *streamPtr;    /* The stream to read from */
  358.     Proc_ControlBlock     *procPtr;    /* This process's control block */
  359.  
  360.     /*
  361.      * Map from stream ID to file pointer and do the read.
  362.      * If the process is not remote, Fs_Read takes care of making
  363.      * the read buffer accessible.
  364.      */
  365.  
  366.     procPtr = Proc_GetEffectiveProc();
  367.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  368.     if (status == SUCCESS) {
  369.     *amountReadPtr = amountRead;
  370.     status = Fs_Read(streamPtr, buffer, streamPtr->offset, amountReadPtr);
  371.     } else {
  372.     *amountReadPtr = 0;
  373.     }
  374.     return(status);
  375. }
  376.  
  377. /*
  378.  *----------------------------------------------------------------------
  379.  *
  380.  * Fs_ReadVectorStub --
  381.  *
  382.  *      The stub for the Fs_ReadVector system call.  Calls Fs_UserReadVector 
  383.  *    to do the work, then copies out the argument to the user's address 
  384.  *    space.
  385.  *
  386.  * Results:
  387.  *    An return status.
  388.  *
  389.  * Side effects:
  390.  *    The amountReadPtr is updated to reflect the amount actually read.
  391.  *
  392.  *----------------------------------------------------------------------
  393.  */
  394.  
  395. ReturnStatus
  396. Fs_ReadVectorStub(streamID, numVectors, userVectorArray, amountReadPtr)
  397.     int        streamID;    /* The user's index into its open file list. */
  398.     int        numVectors;    /* The # of vectors in userVectorArray. */
  399.     Fs_IOVector    userVectorArray[];    
  400.                 /* The vectors defining where and how much to
  401.                  * read. */
  402.     int        *amountReadPtr;    /* The amount of bytes actually read */
  403. {
  404.     ReturnStatus status;
  405.     int        amountRead;
  406.     Fs_IOVector *vectorPtr;
  407.  
  408.     if (numVectors < 0) {
  409.     return(SYS_INVALID_ARG);
  410.     }
  411.  
  412.     /*
  413.      * Copy the I/O vector into kernel space. The buffer addresses in each
  414.      * vector will be made accessible by the Fs_Read routine.
  415.      */
  416.     vectorPtr = (Fs_IOVector *) malloc(numVectors * sizeof(Fs_IOVector));
  417.     if (Vm_CopyIn(numVectors * sizeof(Fs_IOVector), 
  418.            (Address) userVectorArray,
  419.            (Address) vectorPtr) != SUCCESS) {
  420.     free((Address) vectorPtr);
  421.     return(SYS_ARG_NOACCESS);
  422.     }
  423.  
  424.     status = Fs_UserReadVector(streamID, numVectors, vectorPtr, &amountRead);
  425.  
  426.     free((Address) vectorPtr);
  427.     if (Vm_CopyOut(sizeof(int), (Address) &amountRead, 
  428.            (Address) amountReadPtr) != SUCCESS) {
  429.     status = SYS_ARG_NOACCESS;
  430.     }
  431.     return(status);
  432. }
  433.  
  434.  
  435. /*
  436.  *----------------------------------------------------------------------
  437.  *
  438.  * Fs_UserReadVector --
  439.  *
  440.  *      The Fs_ReadVector system call.  Read from the file indicated by
  441.  *      the stream ID into the buffer.  Each I/O vector contains a value
  442.  *      to indicate how much data to read. *AmountReadPtr contains the
  443.  *      total number of bytes read into the vector buffers.
  444.  *      *amountReadPtr will be smaller that the sum of the bufSize fields
  445.  *      in the vector array if an error occurs or an end-of-file is
  446.  *      reached.  A length of zero in *amountReadPtr means an end-of-file
  447.  *      occurred on the first buffer in the vector.
  448.  *
  449.  * Results:
  450.  *    A return status.
  451.  *
  452.  * Side effects:
  453.  *    The *amountReadPtr is updated to reflect the amount actually read.
  454.  *
  455.  *----------------------------------------------------------------------
  456.  */
  457.  
  458. ReturnStatus
  459. Fs_UserReadVector(streamID, numVectors, vectorPtr, amountReadPtr)
  460.     int        streamID;    /* The user's index into its open file list */
  461.     register int numVectors;    /* The # of vectors in vectorArray */
  462.     register Fs_IOVector *vectorPtr;    
  463.                 /* The vectors defining where and how much to 
  464.                  * read. */
  465.     int        *amountReadPtr;    /* Total # of bytes read. */
  466. {
  467.     ReturnStatus    status;
  468.     Fs_Stream        *streamPtr;    /* The stream to read from */
  469.     Proc_ControlBlock     *procPtr;    /* This process's control block */
  470.     register int    sum = 0;    /* Total # of bytes read. */
  471.     register int    i;
  472.  
  473.     /*
  474.      * Map from stream ID to file pointer and do the read.
  475.      * If the process is not remote, Fs_Read takes care of making
  476.      * the read buffer accessible.
  477.      */
  478.  
  479.     procPtr = Proc_GetEffectiveProc();
  480.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  481.  
  482.     if (status == SUCCESS) {
  483.     /*
  484.      * Doing a Fs_Read for each vector buffer is probably not the
  485.      * most efficiennt way to do this, but it is simple.
  486.      */
  487.     for (i= 0; i < numVectors; i++, vectorPtr++) {
  488.  
  489.         status = Fs_Read(streamPtr, vectorPtr->buffer, streamPtr->offset, 
  490.                 &(vectorPtr->bufSize));
  491.         /*
  492.          * Check to see if the read failed or we got an end-of-file.
  493.          */
  494.         if ((status != SUCCESS) || (vectorPtr->bufSize == 0)) {
  495.         break;
  496.         }
  497.         sum += vectorPtr->bufSize;
  498.     }
  499.     }
  500.     *amountReadPtr = sum;
  501.     return(status);
  502. }
  503.  
  504.  
  505. /*
  506.  *----------------------------------------------------------------------
  507.  *
  508.  * Fs_WriteStub --
  509.  *
  510.  *    The Fs_Write system call stub.  Calls Fs_UserWrite to do the
  511.  *    work, then copies out the amount written to the user's address space.
  512.  *
  513.  * Results:
  514.  *    A return status.
  515.  *
  516.  * Side effects:
  517.  *    The writeLengthPtr is updated to reflect the amount actually written.
  518.  *
  519.  *----------------------------------------------------------------------
  520.  */
  521.  
  522. ReturnStatus
  523. Fs_WriteStub(streamID, writeLength, buffer, writeLengthPtr)
  524.     int streamID;
  525.     int writeLength;
  526.     Address buffer;
  527.     int *writeLengthPtr;
  528. {
  529.     register ReturnStatus status;
  530.     Fs_Stream    *streamPtr;    /* The stream to write to */
  531.     Proc_ControlBlock *procPtr;    /* This process's control block */
  532.  
  533.     /*
  534.      * (Begin inlined Fs_UserWrite.)
  535.      */
  536.     /*
  537.      * Map from stream ID to streamPtr.  If the process is not remote,
  538.      * Fs_Write takes care of making the user's buffer accessible.
  539.      */
  540.     procPtr = Proc_GetEffectiveProc();
  541.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  542.     if (status == SUCCESS) {
  543.     status = Fs_Write(streamPtr, buffer, streamPtr->offset, &writeLength);
  544.     } else {
  545.     writeLength = 0;
  546.     }
  547.     /*
  548.      * (End inlined Fs_UserWrite.)
  549.      */
  550.     if (Vm_CopyOut(sizeof(int), (Address) &writeLength, 
  551.            (Address) writeLengthPtr) != SUCCESS) {
  552.     status = SYS_ARG_NOACCESS;
  553.     }
  554.     return(status);
  555. }
  556.  
  557.  
  558. /*
  559.  *----------------------------------------------------------------------
  560.  *
  561.  * Fs_UserWrite --
  562.  *
  563.  *    The user interface to Fs_Write.  Write writeLength characters from
  564.  *    buffer to the file identified by streamID.  *writeLengthPtr
  565.  *    is updated to reflect how much was actually written.
  566.  *
  567.  * Results:
  568.  *    A return status. 
  569.  *
  570.  * Side effects:
  571.  *    The writeLengthPtr is updated to reflect the amount actually written.
  572.  *
  573.  *----------------------------------------------------------------------
  574.  */
  575.  
  576. ReturnStatus
  577. Fs_UserWrite(streamID, writeLength, buffer, writeLengthPtr)
  578.     int streamID;
  579.     int writeLength;
  580.     Address buffer;
  581.     int *writeLengthPtr;
  582. {
  583.     ReturnStatus status;
  584.     Fs_Stream    *streamPtr;    /* The stream to write to */
  585.     Proc_ControlBlock *procPtr;    /* This process's control block */
  586.  
  587.     /*
  588.      * Map from stream ID to streamPtr.  If the process is not remote,
  589.      * Fs_Write takes care of making the user's buffer accessible.
  590.      */
  591.     procPtr = Proc_GetEffectiveProc();
  592.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  593.     if (status == SUCCESS) {
  594.     *writeLengthPtr = writeLength;
  595.     status = Fs_Write(streamPtr, buffer, streamPtr->offset, writeLengthPtr);
  596.     } else {
  597.     *writeLengthPtr = 0;
  598.     }
  599.     return(status);
  600. }
  601.  
  602. /*
  603.  *----------------------------------------------------------------------
  604.  *
  605.  * Fs_WriteVectorStub --
  606.  *
  607.  *      The stub for the Fs_WriteVector system call.  Calls Fs_UserWriteVector 
  608.  *    to do the work, then copies out the argument to the user's address 
  609.  *    space.
  610.  *
  611.  * Results:
  612.  *    An return status.
  613.  *
  614.  * Side effects:
  615.  *    The *amountWrittenPtr is updated to reflect the amount actually read.
  616.  *
  617.  *----------------------------------------------------------------------
  618.  */
  619.  
  620. ReturnStatus
  621. Fs_WriteVectorStub(streamID, numVectors, userVectorArray, amountWrittenPtr)
  622.     int        streamID;    /* The user's index into its open file list. */
  623.     int        numVectors;    /* The # of vectors in userVectorArray. */
  624.     Fs_IOVector    userVectorArray[];    
  625.                 /* The vectors defining where and how much to
  626.                  * write. */
  627.     int    *amountWrittenPtr;    /* The amount of bytes actually written. */
  628. {
  629.     ReturnStatus status;
  630.     int        amountWritten;
  631.     Fs_IOVector *vectorPtr;
  632.  
  633.     if (numVectors < 0) {
  634.     return(SYS_INVALID_ARG);
  635.     }
  636.  
  637.     /*
  638.      * Copy the I/O vector into kernel space. The buffer addresses in each
  639.      * vector will be made accessible by the Fs_Write routine.
  640.      */
  641.     vectorPtr = (Fs_IOVector *) malloc(numVectors * sizeof(Fs_IOVector));
  642.     if (Vm_CopyIn(numVectors * sizeof(Fs_IOVector), 
  643.            (Address) userVectorArray,
  644.            (Address) vectorPtr) != SUCCESS) {
  645.     free((Address) vectorPtr);
  646.     return(SYS_ARG_NOACCESS);
  647.     }
  648.  
  649.     status = Fs_UserWriteVector(streamID, numVectors, vectorPtr, 
  650.             &amountWritten);
  651.  
  652.     free((Address) vectorPtr);
  653.     if (Vm_CopyOut(sizeof(int), (Address) &amountWritten, 
  654.            (Address) amountWrittenPtr) != SUCCESS) {
  655.     status = SYS_ARG_NOACCESS;
  656.     }
  657.     return(status);
  658. }
  659.  
  660.  
  661. /*
  662.  *----------------------------------------------------------------------
  663.  *
  664.  * Fs_UserWriteVector --
  665.  *
  666.  *      The Fs_WriteVector system call.  Write from the file indicated by
  667.  *      the stream ID into the buffer.  Each I/O vector contains a value
  668.  *      to indicate how much data to write. *AmountWrittenPtr contains the
  669.  *      total number of bytes written from the vector buffers.
  670.  *
  671.  * Results:
  672.  *    A return status.
  673.  *
  674.  * Side effects:
  675.  *    The *amountWrittenPtr is updated to reflect the amount 
  676.  *    actually written.
  677.  *
  678.  *----------------------------------------------------------------------
  679.  */
  680.  
  681. ReturnStatus
  682. Fs_UserWriteVector(streamID, numVectors, vectorPtr, amountWrittenPtr)
  683.     int        streamID;    /* The user's index into its open file list */
  684.     register int numVectors;    /* The # of vectors in vectorArray */
  685.     register Fs_IOVector *vectorPtr;    
  686.                 /* The vectors defining where and how much to 
  687.                  * write. */
  688.     int        *amountWrittenPtr;    /* Total # of bytes written. */
  689. {
  690.     ReturnStatus    status;
  691.     Fs_Stream        *streamPtr;    /* The stream to write to. */
  692.     Proc_ControlBlock     *procPtr;    /* This process's control block. */
  693.     register int    sum = 0;    /* Total # of bytes written. */
  694.     register int    i;
  695.  
  696.     /*
  697.      * Map from stream ID to file pointer and do the write.
  698.      * If the process is not remote, Fs_Write takes care of making
  699.      * the write buffer accessible.
  700.      */
  701.  
  702.     procPtr = Proc_GetEffectiveProc();
  703.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  704.  
  705.     if (status == SUCCESS) {
  706.     /*
  707.      * Doing a Fs_Write for each vector buffer is probably not the
  708.      * most efficiennt way to do this, but it is simple.
  709.      */
  710.     for (i= 0; i < numVectors; i++, vectorPtr++) {
  711.  
  712.         status = Fs_Write(streamPtr, vectorPtr->buffer, streamPtr->offset, 
  713.                 &(vectorPtr->bufSize));
  714.         /*
  715.          * Check to see if the write failed or we got an end-of-file.
  716.          */
  717.         if ((status != SUCCESS) || (vectorPtr->bufSize == 0)) {
  718.         break;
  719.         }
  720.         sum += vectorPtr->bufSize;
  721.     }
  722.     }
  723.     *amountWrittenPtr = sum;
  724.     return(status);
  725. }
  726.  
  727. /*
  728.  *----------------------------------------------------------------------
  729.  *
  730.  * Fs_CommandStub --
  731.  *
  732.  *    Stub for the Fs_Command system call.  This copies in a buffer
  733.  *    containing arguments for the particular command, and copies
  734.  *    out whatever Fs_Command leaves in the buffer after its done.
  735.  *
  736.  * Results:
  737.  *    A return code.
  738.  *
  739.  * Side effects:
  740.  *    Call Fs_Command
  741.  *
  742.  *----------------------------------------------------------------------
  743.  */
  744.  
  745. ReturnStatus
  746. Fs_CommandStub(command, bufSize, buffer)
  747.     int command;    /* Defined in user include "test.h" */
  748.     int bufSize;    /* Size in bytes of buffer */
  749.     Address buffer;    /* In/Out - Command specific data */
  750. {
  751.     ReturnStatus status;
  752.     Address localBuffer;
  753.  
  754.     if (bufSize > 0) {
  755.     localBuffer = (Address)malloc(bufSize);
  756.     status = Vm_CopyIn(bufSize, buffer, localBuffer);
  757.     if (status != SUCCESS) {
  758.         free(localBuffer);
  759.         return(status);
  760.     }
  761.     } else {
  762.     localBuffer = (Address)NIL;
  763.     }
  764.  
  765.     status = Fs_Command(command, bufSize, localBuffer);
  766.  
  767.     if (localBuffer != (Address)NIL) {
  768.     if (status == SUCCESS) {
  769.         status = Vm_CopyOut(bufSize, localBuffer, buffer);
  770.     }
  771.     free(localBuffer);
  772.     }
  773.     return(status);
  774. }
  775.  
  776. /*
  777.  *----------------------------------------------------------------------
  778.  *
  779.  * Fs_MakeDeviceStub --
  780.  *
  781.  *    The Fs_MakeDevice system call stub.
  782.  *
  783.  * Results:
  784.  *    Those of Fs_MakeDevice.
  785.  *
  786.  * Side effects:
  787.  *    None.
  788.  *
  789.  *----------------------------------------------------------------------
  790.  */
  791.  
  792. ReturnStatus
  793. Fs_MakeDeviceStub(pathName, devicePtr, permissions)
  794.     char *pathName;        /* Device file to create */
  795.     Fs_Device *devicePtr;    /* Specifies the device file attributes */
  796.     int permissions;        /* Permissions on the special file */
  797. {
  798.     Fs_Device             device;
  799.     int                pathNameLength;
  800.     char            newName[FS_MAX_PATH_NAME_LENGTH];
  801.  
  802.     /*
  803.      * Copy the device name in from user space onto the kernel stack.
  804.      */
  805.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  806.                &pathNameLength) != SUCCESS) {
  807.     return(SYS_ARG_NOACCESS);
  808.     }
  809.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  810.     return(FS_INVALID_ARG);
  811.     }
  812.     if (Vm_CopyIn(sizeof(Fs_Device), (Address)devicePtr, 
  813.           (Address)&device) != SUCCESS) {
  814.     return(SYS_ARG_NOACCESS);
  815.     }
  816.  
  817.     return(Fs_MakeDevice(newName, &device, permissions));
  818. }
  819.  
  820. /*
  821.  *----------------------------------------------------------------------
  822.  *
  823.  * Fs_MakeDirStub --
  824.  *
  825.  *    The Fs_MakeDir system call stub.
  826.  *
  827.  * Results:
  828.  *    Those of Fs_MakeDir.
  829.  *
  830.  * Side effects:
  831.  *    None.
  832.  *
  833.  *----------------------------------------------------------------------
  834.  */
  835.  
  836. ReturnStatus
  837. Fs_MakeDirStub(pathName, permissions)
  838.     char *pathName;
  839.     int permissions;
  840. {
  841.     int            pathNameLength;
  842.     char        newName[FS_MAX_PATH_NAME_LENGTH];
  843.  
  844.     /*
  845.      * Copy the name in from user space to the kernel stack.
  846.      */
  847.  
  848.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  849.                &pathNameLength) != SUCCESS) {
  850.     return(SYS_ARG_NOACCESS);
  851.     }
  852.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  853.     return(FS_INVALID_ARG);
  854.     }
  855.  
  856.     return(Fs_MakeDir(newName, permissions));
  857. }
  858.  
  859. /*
  860.  *----------------------------------------------------------------------
  861.  *
  862.  * Fs_RemoveStub --
  863.  *
  864.  *    The stub for the Fs_Remove system call.
  865.  *
  866.  * Results:
  867.  *    Those of Fs_Remove.
  868.  *
  869.  * Side effects:
  870.  *    None.
  871.  *
  872.  *----------------------------------------------------------------------
  873.  */
  874.  
  875. ReturnStatus
  876. Fs_RemoveStub(pathName)
  877.     char *pathName;
  878. {
  879.     int            pathNameLength;
  880.     char        newName[FS_MAX_PATH_NAME_LENGTH];
  881.  
  882.     /*
  883.      * Copy the name in from user space to the kernel stack.
  884.      */
  885.  
  886.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  887.                &pathNameLength) != SUCCESS) {
  888.     return(SYS_ARG_NOACCESS);
  889.     }
  890.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  891.     return(FS_INVALID_ARG);
  892.     }
  893.  
  894.     return(Fs_Remove(newName));
  895. }
  896.  
  897. /*
  898.  *----------------------------------------------------------------------
  899.  *
  900.  * Fs_RemoveDirStub --
  901.  *
  902.  *    The Fs_RemoveDir system call stub.
  903.  *
  904.  * Results:
  905.  *    The results of Fs_RemoveDir.
  906.  *
  907.  * Side effects:
  908.  *    None.
  909.  *
  910.  *----------------------------------------------------------------------
  911.  */
  912.  
  913. ReturnStatus
  914. Fs_RemoveDirStub(pathName)
  915.     char *pathName;
  916. {
  917.     int        pathNameLength;
  918.     char    newName[FS_MAX_PATH_NAME_LENGTH];
  919.  
  920.     /*
  921.      * Copy the name in from user space onto the kernel stack.
  922.      */
  923.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  924.                &pathNameLength) != SUCCESS) {
  925.     return(SYS_ARG_NOACCESS);
  926.     }
  927.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  928.     return(FS_INVALID_ARG);
  929.     }
  930.  
  931.     return(Fs_RemoveDir(newName));
  932. }
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * Fs_ChangeDirStub --
  938.  *
  939.  *    The stub for the system call that changes the current directory.
  940.  *    The argument specifies a new current directory.  The argument
  941.  *    can be a relative path name.
  942.  *
  943.  * Results:
  944.  *    None.
  945.  *
  946.  * Side effects:
  947.  *    None.
  948.  *
  949.  *----------------------------------------------------------------------
  950.  */
  951.  
  952. ReturnStatus
  953. Fs_ChangeDirStub(pathName)
  954.     char *pathName;
  955. {
  956.     int        pathNameLength;
  957.     char    newName[FS_MAX_PATH_NAME_LENGTH];
  958.  
  959.     /*
  960.      * Copy the name in from user space onto the kernel stack.
  961.      */
  962.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  963.                &pathNameLength) != SUCCESS) {
  964.     return(SYS_ARG_NOACCESS);
  965.     }
  966.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  967.     return(FS_INVALID_ARG);
  968.     }
  969.  
  970.     return(Fs_ChangeDir(newName));
  971. }
  972.  
  973. /*
  974.  *----------------------------------------------------------------------
  975.  *
  976.  * Fs_GetNewIDStub --
  977.  *
  978.  *    The stub for the system call that duplicates a stream ID.
  979.  *    See Fs_GetNewID.
  980.  *
  981.  * Results:
  982.  *    A return status.
  983.  *
  984.  * Side effects:
  985.  *    None.
  986.  *
  987.  *----------------------------------------------------------------------
  988.  */
  989. ReturnStatus
  990. Fs_GetNewIDStub(streamID, newStreamIDPtr)
  991.     int streamID;
  992.     int *newStreamIDPtr;
  993. {
  994.     ReturnStatus     status;
  995.     int         newStreamID;
  996.  
  997.     if (Vm_CopyIn(sizeof(int), (Address) newStreamIDPtr, 
  998.           (Address) &newStreamID) != SUCCESS) {
  999.     return(SYS_ARG_NOACCESS);
  1000.     }
  1001.     status = Fs_GetNewID(streamID, &newStreamID);
  1002.     if (status != SUCCESS) {
  1003.     return(status);
  1004.     }
  1005.  
  1006.     if (Vm_CopyOut(sizeof(int), (Address) &newStreamID, 
  1007.             (Address) newStreamIDPtr) != SUCCESS) {
  1008.     return(SYS_ARG_NOACCESS);
  1009.     } else {
  1010.     return(SUCCESS);
  1011.     }
  1012. }
  1013.  
  1014.  
  1015. /*
  1016.  *----------------------------------------------------------------------
  1017.  *
  1018.  * Fs_GetAttributesStub --
  1019.  *
  1020.  *    Stub for the Fs_GetAttributes system call.
  1021.  *
  1022.  * Results:
  1023.  *    The attributes for the named file.
  1024.  *
  1025.  * Side effects:
  1026.  *    *attrPtr is filled in with the attributes of the file.
  1027.  *
  1028.  *----------------------------------------------------------------------
  1029.  */
  1030. ReturnStatus
  1031. Fs_GetAttributesStub(pathName, fileOrLink, attrPtr)
  1032.     char *pathName;
  1033.     int fileOrLink;
  1034.     Fs_Attributes *attrPtr;
  1035. {
  1036.     ReturnStatus     status;
  1037.     Fs_Attributes    attributes;
  1038.     int            pathNameLength;
  1039.     char        newName[FS_MAX_PATH_NAME_LENGTH];
  1040.  
  1041.     /*
  1042.      * Copy the name in from user space onto the kernel stack.
  1043.      */
  1044.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  1045.                &pathNameLength) != SUCCESS) {
  1046.     return(SYS_ARG_NOACCESS);
  1047.     }
  1048.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1049.     return(FS_INVALID_ARG);
  1050.     }
  1051.  
  1052.     status = Fs_GetAttributes(newName, fileOrLink, &attributes);
  1053.     if (status != SUCCESS) {
  1054.     return(status);
  1055.     }
  1056.  
  1057.     if (Vm_CopyOut(sizeof(attributes), (Address) &attributes, 
  1058.            (Address) attrPtr) != SUCCESS) {
  1059.     return(SYS_ARG_NOACCESS);
  1060.     } else {
  1061.     return(SUCCESS);
  1062.     }
  1063. }
  1064.  
  1065.  
  1066. /*
  1067.  *----------------------------------------------------------------------
  1068.  *
  1069.  * Fs_CheckAccess --
  1070.  *
  1071.  *    Process the Fs_CheckAccess system all.
  1072.  *
  1073.  * Results:
  1074.  *    SYS_ARG_NOACCESS if pathname not accessible.
  1075.  *    FS_INVALID_ARG if pathname too long.
  1076.  *    Otherwise:
  1077.  *        SUCCESS if accessible.
  1078.  *        FS_NO_ACCESS if not accessible.
  1079.  *
  1080.  * Side effects:
  1081.  *    None.
  1082.  *
  1083.  *----------------------------------------------------------------------
  1084.  */
  1085. ReturnStatus
  1086. Fs_CheckAccess(pathName, perm, useRealID)
  1087.     char     *pathName;
  1088.     int        perm;
  1089.     Boolean    useRealID;
  1090. {
  1091.     ReturnStatus    status;
  1092.     Fs_Attributes    attributes;
  1093.     Proc_ControlBlock    *procPtr;
  1094.     int            pathNameLength;
  1095.     char        newName[FS_MAX_PATH_NAME_LENGTH];
  1096.     register int    bits;
  1097.  
  1098.     /*
  1099.      * Copy the name in from user space onto the kernel stack.
  1100.      */
  1101.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  1102.                &pathNameLength) != SUCCESS) {
  1103.     return(SYS_ARG_NOACCESS);
  1104.     }
  1105.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1106.     return(FS_INVALID_ARG);
  1107.     }
  1108.  
  1109.     procPtr = Proc_GetEffectiveProc();
  1110.  
  1111.     status = Fs_GetAttributes(newName, FS_ATTRIB_FILE, &attributes);
  1112.     if (status != SUCCESS) {
  1113.     return(status);
  1114.     } else if (perm == FS_EXISTS) {
  1115.     /*
  1116.      * Only checking for existence, not read or write access.
  1117.      */
  1118.     return(SUCCESS);
  1119.     } else if ((useRealID && (procPtr->userID == 0)) ||
  1120.         (!useRealID && (procPtr->effectiveUserID == 0))) {
  1121.     /*
  1122.      * Let the super-user do anything.
  1123.      */
  1124.     return(SUCCESS);
  1125.     }
  1126.     /*
  1127.      * Translate from FS_READ etc, into permission bits, ie. FS_WORLD_READ.
  1128.      * The world permissions are shifted left to the owner or group permissions
  1129.      * if the process's userID or one of its group IDs matches the file's.
  1130.      */
  1131.     bits = 0;
  1132.     if (perm & FS_READ) {
  1133.     bits |= FS_WORLD_READ;
  1134.     }
  1135.     if (perm & FS_WRITE) {
  1136.     bits |= FS_WORLD_WRITE;
  1137.     }
  1138.     if (perm & FS_EXECUTE) {
  1139.     bits |= FS_WORLD_EXEC;
  1140.     }
  1141.  
  1142.     if ((useRealID && attributes.uid == procPtr->userID) ||
  1143.         (!useRealID && attributes.uid == procPtr->effectiveUserID)) {
  1144.     bits <<= 6;
  1145.     } else {
  1146.     int    i;
  1147.     for (i = 0; i < procPtr->fsPtr->numGroupIDs; i++) {
  1148.         if (attributes.gid == procPtr->fsPtr->groupIDs[i]) {
  1149.         bits <<= 3;
  1150.         break;
  1151.         }
  1152.     }
  1153.     }
  1154.     if ((attributes.permissions & bits) == bits) {
  1155.     return (GEN_SUCCESS);
  1156.     } else {
  1157.     return (FS_NO_ACCESS);
  1158.     }
  1159. }
  1160.  
  1161.  
  1162. /*
  1163.  *----------------------------------------------------------------------
  1164.  *
  1165.  * Fs_GetAttributesIDStub --
  1166.  *
  1167.  *    Stub for the Fs_GetAttributesID system call.
  1168.  *
  1169.  * Results:
  1170.  *    Get the attributes for the file referred to by the specified
  1171.  *    descriptor.
  1172.  *
  1173.  * Side effects:
  1174.  *     *attrPtr is filled in with the attributes of the file.
  1175.  *
  1176.  *----------------------------------------------------------------------
  1177.  */
  1178. ReturnStatus
  1179. Fs_GetAttributesIDStub(streamID, attrPtr)
  1180.     int        streamID;    /* The user's index into its open file list */
  1181.     Fs_Attributes *attrPtr;    /* point to buffer to hold attributes */
  1182. {
  1183.     register    ReturnStatus     status;
  1184.     Fs_Stream            *streamPtr;
  1185.     Fs_Attributes         attributes;
  1186.  
  1187.     status = Fs_GetStreamPtr(Proc_GetEffectiveProc(), streamID, &streamPtr);
  1188.     if (status != SUCCESS) {
  1189.     return(status);
  1190.     }
  1191.     status = Fs_GetAttrStream(streamPtr, &attributes);
  1192.     if (status != SUCCESS) {
  1193.     return(status);
  1194.     }
  1195.  
  1196.     if (Vm_CopyOut(sizeof(attributes), (Address) &attributes, 
  1197.            (Address) attrPtr) != SUCCESS) {
  1198.     return(SYS_ARG_NOACCESS);
  1199.     } else {
  1200.     return(SUCCESS);
  1201.     }
  1202. }
  1203.  
  1204. /*
  1205.  *----------------------------------------------------------------------
  1206.  *
  1207.  * Fs_SetAttributesStub --
  1208.  *
  1209.  *    Stub for Fs_SetAttributes system call.  This is a general
  1210.  *    routine that sets ownership, access & modify times, permissions,
  1211.  *    and user-defined file type.  The calling process must own the file.    
  1212.  *
  1213.  * Results:
  1214.  *    A return status.
  1215.  *
  1216.  * Side effects:
  1217.  *    None here in this stub.
  1218.  *
  1219.  *----------------------------------------------------------------------
  1220.  */
  1221. ReturnStatus
  1222. Fs_SetAttributesStub(pathName, fileOrLink, attrPtr)
  1223.     char *pathName;
  1224.     int fileOrLink;
  1225.     Fs_Attributes *attrPtr;
  1226. {
  1227.     int                pathNameLength;
  1228.     Fs_Attributes        attr;
  1229.     char            newName[FS_MAX_PATH_NAME_LENGTH];
  1230.  
  1231.     if (Vm_CopyIn(sizeof(attr), (Address) attrPtr, 
  1232.           (Address) &attr) != SUCCESS) {
  1233.     return(SYS_ARG_NOACCESS);
  1234.     }
  1235.     /*
  1236.      * Copy the name in from user space onto the kernel stack.
  1237.      */
  1238.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  1239.                &pathNameLength) != SUCCESS) {
  1240.     return(SYS_ARG_NOACCESS);
  1241.     }
  1242.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1243.     return(FS_INVALID_ARG);
  1244.     }
  1245.  
  1246.     return(Fs_SetAttributes(newName, fileOrLink, &attr, FS_SET_ALL_ATTRS));
  1247. }
  1248.  
  1249. /*
  1250.  *----------------------------------------------------------------------
  1251.  *
  1252.  * Fs_SetAttrStub --
  1253.  *
  1254.  *    Stub for Fs_SetAttr system call.  Like the old Fs_SetAttributes
  1255.  *    but with an additional flag specifying exactly which attributes
  1256.  *    to update.
  1257.  *
  1258.  * Results:
  1259.  *    A return status.
  1260.  *
  1261.  * Side effects:
  1262.  *    None.
  1263.  *
  1264.  *----------------------------------------------------------------------
  1265.  */
  1266. ReturnStatus
  1267. Fs_SetAttrStub(pathName, fileOrLink, attrPtr, flags)
  1268.     char *pathName;        /* Name of file to manipulate */
  1269.     int fileOrLink;        /* Whether or not to follow symbolic links */
  1270.     Fs_Attributes *attrPtr;    /* New values for attributes */
  1271.     int flags;            /* What attributes to set */
  1272. {
  1273.     int                pathNameLength;
  1274.     Fs_Attributes        attr;
  1275.     char            newName[FS_MAX_PATH_NAME_LENGTH];
  1276.  
  1277.     if (Vm_CopyIn(sizeof(attr), (Address) attrPtr, 
  1278.           (Address) &attr) != SUCCESS) {
  1279.     return(SYS_ARG_NOACCESS);
  1280.     }
  1281.     /*
  1282.      * Copy the name in from user space onto the kernel stack.
  1283.      */
  1284.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newName,
  1285.                &pathNameLength) != SUCCESS) {
  1286.     return(SYS_ARG_NOACCESS);
  1287.     }
  1288.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1289.     return(FS_INVALID_ARG);
  1290.     }
  1291.  
  1292.     return(Fs_SetAttributes(newName, fileOrLink, &attr, flags));
  1293. }
  1294.  
  1295. /*
  1296.  *----------------------------------------------------------------------
  1297.  *
  1298.  * Fs_SetAttributesIDStub --
  1299.  *
  1300.  *    Stub for Fs_SetAttributesID system call.
  1301.  *
  1302.  * Results:
  1303.  *    A return status.
  1304.  *
  1305.  * Side effects:
  1306.  *    None.
  1307.  *
  1308.  *----------------------------------------------------------------------
  1309.  */
  1310. ReturnStatus
  1311. Fs_SetAttributesIDStub(streamID, attrPtr)
  1312.     int streamID;
  1313.     Fs_Attributes *attrPtr;
  1314. {
  1315.     register     ReturnStatus     status;
  1316.     Fs_Stream            *streamPtr;
  1317.     Fs_Attributes        attr;
  1318.     Fs_UserIDs            ids;
  1319.     Proc_ControlBlock        *procPtr;
  1320.  
  1321.     if (Vm_CopyIn(sizeof(attr), (Address) attrPtr, 
  1322.           (Address) &attr) != SUCCESS) {
  1323.     return(SYS_ARG_NOACCESS);
  1324.     }
  1325.  
  1326.     /*
  1327.      * Map from stream ID to file pointer and get the attributes.
  1328.      */
  1329.     procPtr = Proc_GetEffectiveProc();
  1330.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  1331.     if (status == SUCCESS) {
  1332.     Fs_SetIDs(procPtr, &ids);
  1333.     status = Fs_SetAttrStream(streamPtr, &attr, &ids, FS_SET_ALL_ATTRS);
  1334.     }
  1335.     return(status);
  1336. }
  1337.  
  1338. /*
  1339.  *----------------------------------------------------------------------
  1340.  *
  1341.  * Fs_SetAttrIDStub --
  1342.  *
  1343.  *    Stub for Fs_SetAttrID system call.  Like Fs_SetAttributesID
  1344.  *    but has a flag parameter that specifies what attrs to set.
  1345.  *
  1346.  * Results:
  1347.  *    A return status.
  1348.  *
  1349.  * Side effects:
  1350.  *    None.
  1351.  *
  1352.  *----------------------------------------------------------------------
  1353.  */
  1354. ReturnStatus
  1355. Fs_SetAttrIDStub(streamID, attrPtr, flags)
  1356.     int streamID;        /* References file to manipulate */
  1357.     Fs_Attributes *attrPtr;    /* New attributes for the file */
  1358.     int flags;            /* What attributes to set */
  1359. {
  1360.     register     ReturnStatus     status;
  1361.     Fs_Stream            *streamPtr;
  1362.     Fs_Attributes        attr;
  1363.     Fs_UserIDs            ids;
  1364.     Proc_ControlBlock        *procPtr;
  1365.  
  1366.     if (Vm_CopyIn(sizeof(attr), (Address) attrPtr, 
  1367.           (Address) &attr) != SUCCESS) {
  1368.     return(SYS_ARG_NOACCESS);
  1369.     }
  1370.  
  1371.     /*
  1372.      * Map from stream ID to file pointer and get the attributes.
  1373.      */
  1374.     procPtr = Proc_GetEffectiveProc();
  1375.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  1376.     if (status == SUCCESS) {
  1377.     Fs_SetIDs(procPtr, &ids);
  1378.     status = Fs_SetAttrStream(streamPtr, &attr, &ids, flags);
  1379.     }
  1380.     return(status);
  1381. }
  1382.  
  1383. /*
  1384.  *----------------------------------------------------------------------
  1385.  *
  1386.  * Fs_SetDefPermStub --
  1387.  *
  1388.  *    Set the default permissions on files created by this process.
  1389.  *    These defaults get inherited by child processes.
  1390.  *
  1391.  * Results:
  1392.  *    A return status.
  1393.  *
  1394.  * Side effects:
  1395.  *    Sets the default permissions mask in the filesystem related
  1396.  *    state kept in the proc table.
  1397.  *
  1398.  *----------------------------------------------------------------------
  1399.  */
  1400. ReturnStatus
  1401. Fs_SetDefPermStub(permissions, oldPermPtr)
  1402.     int permissions;    /*  A mask of 9 permission bits.  Three sets of 3
  1403.              * bits.  The first set is for the owner's permissions,
  1404.              * the second for the group's, and the last is for
  1405.              * everyone else.  The three bits indicate read,
  1406.              * write, and execute permissions, respectively.
  1407.              * A permission bit set in this mask ENABLES the
  1408.              * permission on created files. */
  1409.     int *oldPermPtr;    /* Output, the previous value of the permissions mask */
  1410. {
  1411.     register    Proc_ControlBlock    *procPtr;
  1412.     int                 oldPerm;
  1413.  
  1414.     procPtr = Proc_GetEffectiveProc();
  1415.     oldPerm = procPtr->fsPtr->filePermissions;
  1416.     procPtr->fsPtr->filePermissions = (unsigned int)(permissions & 0777);
  1417.     if (Proc_ByteCopy(FALSE, sizeof(int), (Address)&oldPerm, 
  1418.         (Address)oldPermPtr) != SUCCESS) {
  1419.     return(SYS_ARG_NOACCESS);
  1420.     } else {
  1421.     return(SUCCESS);
  1422.     }
  1423. }
  1424.  
  1425. /*
  1426.  *----------------------------------------------------------------------
  1427.  *
  1428.  * Fs_HardLinkStub --
  1429.  *
  1430.  *    Stub for the Fs_HardLink system call.
  1431.  *
  1432.  * Results:
  1433.  *    A return status.
  1434.  *
  1435.  * Side effects:
  1436.  *    None.
  1437.  *
  1438.  *----------------------------------------------------------------------
  1439.  */
  1440. ReturnStatus
  1441. Fs_HardLinkStub(fileName, linkName)
  1442.     char *fileName;    /* Name of the existing file */
  1443.     char *linkName;    /* New name to link to the existing file */
  1444. {
  1445.     ReturnStatus     status = SUCCESS;
  1446.     int            fileNameLength;
  1447.     int            linkNameLength;
  1448.     char        newFileName[FS_MAX_PATH_NAME_LENGTH];
  1449.     char        *newLinkName;
  1450.  
  1451.     /*
  1452.      * Copy the filename in from user space onto the kernel stack.
  1453.      */
  1454.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, fileName, newFileName,
  1455.                &fileNameLength) != SUCCESS) {
  1456.     return(SYS_ARG_NOACCESS);
  1457.     }
  1458.     if (fileNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1459.     return(FS_INVALID_ARG);
  1460.     }
  1461.  
  1462.     /*
  1463.      * Maybe I could put the link name onto the stack as well but I am 
  1464.      * allocing it here because I'm not sure if the stack is big enough.
  1465.      * Should just make the stack bigger I suppose ...
  1466.      */
  1467.     newLinkName = (char  *) malloc(FS_MAX_PATH_NAME_LENGTH);
  1468.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, linkName, newLinkName,
  1469.                &linkNameLength) == SUCCESS) {
  1470.     if (linkNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1471.         status = FS_INVALID_ARG;
  1472.     } else {
  1473.         status = Fs_HardLink(newFileName, newLinkName);
  1474.     }
  1475.     } else {
  1476.     status = SYS_ARG_NOACCESS;
  1477.     }
  1478.  
  1479.     free((Address) newLinkName);
  1480.  
  1481.     return(status);
  1482. }
  1483.  
  1484.  
  1485. /*
  1486.  *----------------------------------------------------------------------
  1487.  *
  1488.  * Fs_RenameStub --
  1489.  *
  1490.  *    Stub for Fs_Rename system call.
  1491.  *
  1492.  * Results:
  1493.  *    A return status.
  1494.  *
  1495.  * Side effects:
  1496.  *    None.
  1497.  *
  1498.  *----------------------------------------------------------------------
  1499.  */
  1500. ReturnStatus
  1501. Fs_RenameStub(pathName, newName)
  1502.     char *pathName;
  1503.     char *newName;
  1504. {
  1505.     ReturnStatus    status;
  1506.     int            pathNameLength;
  1507.     int            newNameLength;
  1508.     char        newPathName[FS_MAX_PATH_NAME_LENGTH];
  1509.     char        *newNewName;
  1510.  
  1511.     /*
  1512.      * Copy the name in from user space onto the kernel stack.
  1513.      */
  1514.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, pathName, newPathName,
  1515.                &pathNameLength) != SUCCESS) {
  1516.     return(SYS_ARG_NOACCESS);
  1517.     }
  1518.     if (pathNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1519.     return(FS_INVALID_ARG);
  1520.     }
  1521.  
  1522.     /*
  1523.      * Maybe I could put the new name onto the stack as well but I am 
  1524.      * allocing it here because I'm not sure if the stack is big enough.
  1525.      * Should just make the stack bigger I suppose ...
  1526.      */
  1527.     newNewName = (char  *) malloc(FS_MAX_PATH_NAME_LENGTH);
  1528.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, newName, newNewName,
  1529.                &newNameLength) == SUCCESS) {
  1530.     if (newNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1531.         status = FS_INVALID_ARG;
  1532.     } else {
  1533.         status = Fs_Rename(newPathName, newNewName);
  1534.     }
  1535.     } else {
  1536.     status = SYS_ARG_NOACCESS;
  1537.     }
  1538.  
  1539.     free((Address) newNewName);
  1540.  
  1541.     return(status);
  1542. }
  1543.  
  1544.  
  1545. /*
  1546.  *----------------------------------------------------------------------
  1547.  *
  1548.  * Fs_SymLinkStub --
  1549.  *
  1550.  *    Stub for Fs_SymLink system call.
  1551.  *
  1552.  * Results:
  1553.  *    None.
  1554.  *
  1555.  * Side effects:
  1556.  *    None.
  1557.  *
  1558.  *----------------------------------------------------------------------
  1559.  */
  1560. ReturnStatus
  1561. Fs_SymLinkStub(targetName, linkName, remoteFlag)
  1562.     char *targetName;
  1563.     char *linkName;
  1564.     Boolean remoteFlag;
  1565. {
  1566.     ReturnStatus    status;
  1567.     int            targetNameLength;
  1568.     int            linkNameLength;
  1569.     char        newTargetName[FS_MAX_PATH_NAME_LENGTH];
  1570.     char        *newLinkName;
  1571.  
  1572.     /*
  1573.      * Copy the name in from user space onto the kernel stack.
  1574.      */
  1575.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, targetName, newTargetName,
  1576.                &targetNameLength) != SUCCESS) {
  1577.     return(SYS_ARG_NOACCESS);
  1578.     }
  1579.     if (targetNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1580.     return(FS_INVALID_ARG);
  1581.     }
  1582.  
  1583.     /*
  1584.      * Maybe I could put the new name onto the stack as well but I am 
  1585.      * allocing it here because I'm not sure if the stack is big enough.
  1586.      * Should just make the stack bigger I suppose ...
  1587.      */
  1588.     newLinkName = (char  *) malloc(FS_MAX_PATH_NAME_LENGTH);
  1589.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, linkName, newLinkName,
  1590.                &linkNameLength) == SUCCESS) {
  1591.     if (linkNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1592.         status = FS_INVALID_ARG;
  1593.     } else {
  1594.         status = Fs_SymLink(newTargetName, newLinkName, remoteFlag);
  1595.     }
  1596.     } else {
  1597.     status = SYS_ARG_NOACCESS;
  1598.     }
  1599.     free((Address) newLinkName);
  1600.  
  1601.     return(status);
  1602. }
  1603.  
  1604.  
  1605. /*
  1606.  *----------------------------------------------------------------------
  1607.  *
  1608.  * Fs_ReadLinkStub --
  1609.  *
  1610.  *    Stub for Fs_ReadLink system call.  The named file should be a
  1611.  *    remote link or a symbolic link file.  It is opened and its
  1612.  *    contents (another file's name) are read and stored in the buffer.
  1613.  *
  1614.  * Results:
  1615.  *    A return code from the open and read.
  1616.  *
  1617.  * Side effects:
  1618.  *    Fills in the buffer with contents of the link file, and
  1619.  *    returns the amount of data stored there in *linkSizePtr.
  1620.  *
  1621.  *----------------------------------------------------------------------
  1622.  */
  1623. ReturnStatus
  1624. Fs_ReadLinkStub(linkName, bufSize, buffer, linkSizePtr)
  1625.     char *linkName;        /* Name of the link file */
  1626.     int bufSize;        /* Size of the user's buffer */
  1627.     char *buffer;        /* The buffer to hold the link's value */
  1628.     int *linkSizePtr;        /* Return, the amount of data in buffer */
  1629. {
  1630.     ReturnStatus    status;
  1631.     Fs_Stream        *streamPtr;
  1632.     int            linkNameLength;
  1633.     char        newLinkName[FS_MAX_PATH_NAME_LENGTH];
  1634.  
  1635.     /*
  1636.      * Copy the name in from user space onto the kernel stack.
  1637.      */
  1638.     if (Fsutil_StringNCopy(FS_MAX_PATH_NAME_LENGTH, linkName, newLinkName,
  1639.                &linkNameLength) != SUCCESS) {
  1640.     return(SYS_ARG_NOACCESS);
  1641.     }
  1642.     if (linkNameLength == FS_MAX_PATH_NAME_LENGTH) {
  1643.     return(FS_INVALID_ARG);
  1644.     }
  1645.  
  1646.     status = Fs_Open(newLinkName, FS_READ | FS_USER,
  1647.              FS_SYMBOLIC_LINK|FS_REMOTE_LINK, 0, &streamPtr);
  1648.     if (status == SUCCESS) {
  1649.     status = Fs_Read(streamPtr, buffer, 0, &bufSize);
  1650.     if (status == SUCCESS) {
  1651.         /*
  1652.          * Sprite's link count includes the terminating null character
  1653.          * in the character count return while Unix doesn't.  Make our
  1654.          * count backward-compatible with Unix.
  1655.          */
  1656.          status = Proc_ByteCopy(TRUE, sizeof(int), (Address) &bufSize,
  1657.             (Address) &linkNameLength);
  1658.         if (status == SUCCESS) {
  1659.         if (linkNameLength >= FS_MAX_PATH_NAME_LENGTH) {
  1660.             status = FS_INVALID_ARG;
  1661.         } else {
  1662.             status = Proc_ByteCopy(TRUE, linkNameLength,
  1663.                 (Address) buffer, (Address) newLinkName);
  1664.             if (status == SUCCESS &&
  1665.                 newLinkName[linkNameLength-1] == '\0') {
  1666.             linkNameLength--;
  1667.             status = Proc_ByteCopy(FALSE, sizeof(int),
  1668.                 (Address) &linkNameLength, (Address) &bufSize);
  1669.             }
  1670.         }
  1671.         }
  1672.         status = Proc_ByteCopy(FALSE, sizeof(int), (Address)&linkNameLength,
  1673.                    (Address)linkSizePtr);
  1674.     }
  1675.     (void)Fs_Close(streamPtr);
  1676.     }
  1677.     return(status);
  1678. }
  1679.  
  1680. /*
  1681.  *----------------------------------------------------------------------
  1682.  *
  1683.  * Fs_IOControlStub --
  1684.  *
  1685.  *    Stub for the Fs_IOControl system call.  IOControl commands
  1686.  *    that affect Fs_Stream objects are done here.  The rest of
  1687.  *    the commands are passed down to the stream type specific
  1688.  *    IOControl procedures.
  1689.  *
  1690.  * Results:
  1691.  *    A return status.  The output buffer is modified with results
  1692.  *    for the command.  The format of the various results is explained
  1693.  *    in user/fs.h for generic operations, and in dev/ *.h for
  1694.  *    device specific operations.
  1695.  *
  1696.  * Side effects:
  1697.  *    Depends on the command.
  1698.  *
  1699.  *----------------------------------------------------------------------
  1700.  */
  1701.  
  1702. ReturnStatus
  1703. Fs_IOControlStub(streamID, command, inBufSize, inBuffer,
  1704.                outBufSize, outBuffer)
  1705.     int     streamID;    /* User's handle on the stream */
  1706.     int     command;    /* IOControl command */
  1707.     int     inBufSize;    /* Size of inBuffer */
  1708.     Address     inBuffer;    /* Command specific input parameters */
  1709.     int     outBufSize;    /* Size of outBuffer */
  1710.     Address     outBuffer;    /* Command specific output parameters */
  1711. {
  1712.     Proc_ControlBlock *procPtr;
  1713.     Fs_ProcessState *fsPtr;
  1714.     Fs_Stream      *streamPtr;
  1715.     register ReturnStatus status = SUCCESS;
  1716.     Address    localInBuffer = (Address)NIL;
  1717.     Address    localOutBuffer = (Address)NIL;
  1718.     Fs_IOCParam ioctl;
  1719.     Fs_IOReply reply;
  1720.  
  1721.     /*
  1722.      * Get a stream pointer.
  1723.      */
  1724.     procPtr = Proc_GetEffectiveProc();
  1725.     status = Fs_GetStreamPtr(procPtr, streamID, &streamPtr);
  1726.     if (status != SUCCESS) {
  1727.     return(status);
  1728.     }
  1729.  
  1730.     if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
  1731.     return(FS_STALE_HANDLE);
  1732.     }
  1733.  
  1734.     ioctl.command = command;
  1735.     ioctl.format = mach_Format;
  1736.     ioctl.procID = procPtr->processID;
  1737.     ioctl.familyID = procPtr->familyID;
  1738.     ioctl.uid = procPtr->effectiveUserID;
  1739.  
  1740.     /*
  1741.      * Fast path for non-generic I/O controls to pseudo-devices.
  1742.      * We don't copy in/out the user's parameter blocks because the
  1743.      * pseudo-device code does direct cross-address-space copy later.
  1744.      * We also skip the check against large parameter blocks so arbitrary
  1745.      * amounts of data can be fed to and from a pseudo-device.
  1746.      */
  1747.     if ((streamPtr->ioHandlePtr->fileID.type == FSIO_LCL_PSEUDO_STREAM) &&
  1748.     (command > IOC_GENERIC_LIMIT)) {
  1749.     ioctl.inBufSize = inBufSize;
  1750.     ioctl.inBuffer = inBuffer;
  1751.     ioctl.outBufSize = outBufSize;  
  1752.     ioctl.outBuffer = outBuffer;
  1753.     ioctl.flags = FS_USER_IN|FS_USER_OUT;
  1754.     return(Fs_IOControl(streamPtr, &ioctl, &reply));
  1755.     }
  1756.  
  1757.     if (inBufSize > IOC_MAX_BYTES || outBufSize > IOC_MAX_BYTES) {
  1758.     return(SYS_INVALID_ARG);
  1759.     }
  1760.     ioctl.flags = 0;    /* We'll copy buffer's into/out of the kernel */
  1761.  
  1762.     /*
  1763.      * The input parameters are copied into kernel
  1764.      * space, and the results are copied back out so that the
  1765.      * lower level routines don't have to worry about it.
  1766.      */
  1767.     if ((outBufSize > 0) && (outBuffer != (Address)0) &&
  1768.                 (outBuffer != (Address)NIL)){
  1769.     ioctl.outBuffer = localOutBuffer = (Address) malloc(outBufSize);
  1770.     ioctl.outBufSize = outBufSize;
  1771.     } else {
  1772.     ioctl.outBuffer = (Address)NIL;
  1773.     ioctl.outBufSize = outBufSize = 0;
  1774.     }
  1775.     if ((inBufSize > 0) && (inBuffer != (Address)0) &&
  1776.                (inBuffer != (Address)NIL)) {
  1777.     ioctl.inBuffer  = localInBuffer = (Address) malloc(inBufSize);
  1778.     ioctl.inBufSize = inBufSize;
  1779.     } else {
  1780.     ioctl.inBuffer = (Address)NIL;
  1781.     ioctl.inBufSize = 0;
  1782.     }
  1783.  
  1784.     if (ioctl.inBufSize &&
  1785.     Vm_CopyIn(ioctl.inBufSize, inBuffer, ioctl.inBuffer) != SUCCESS) {
  1786.     status = SYS_ARG_NOACCESS;
  1787.     } else {
  1788.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  1789.     if (status == SUCCESS) {
  1790.         /*
  1791.          * Post process the set/get flags stuff because the close-on-exec
  1792.          * flag is not kept down at the stream level, but up along
  1793.          * with the streamID.
  1794.          */
  1795.         fsPtr = procPtr->fsPtr;
  1796.         switch(command) {
  1797.         case IOC_GET_FLAGS: {
  1798.             if (fsPtr->streamFlags[streamID] & FS_CLOSE_ON_EXEC) {
  1799.             *(int *)ioctl.outBuffer |= IOC_CLOSE_ON_EXEC;
  1800.             }
  1801.             break;
  1802.         }
  1803.         case IOC_SET_BITS:
  1804.         case IOC_SET_FLAGS: {
  1805.             int flags;
  1806.             flags = *(int *)ioctl.inBuffer;
  1807.  
  1808.             if (flags & IOC_CLOSE_ON_EXEC) {
  1809.             fsPtr->streamFlags[streamID] |= FS_CLOSE_ON_EXEC;
  1810.             } else if (command == IOC_SET_FLAGS) {
  1811.             fsPtr->streamFlags[streamID] &= ~FS_CLOSE_ON_EXEC;
  1812.             }
  1813.             break;
  1814.         }
  1815.         case IOC_CLEAR_BITS:{
  1816.             int flags;
  1817.             flags = *(int *)ioctl.inBuffer;
  1818.             if (flags & IOC_CLOSE_ON_EXEC) {
  1819.             fsPtr->streamFlags[streamID] &= ~FS_CLOSE_ON_EXEC;
  1820.             }
  1821.             break;
  1822.         }
  1823.         }
  1824.         if (outBufSize) {
  1825.         status = Vm_CopyOut(reply.length, ioctl.outBuffer,
  1826.                     outBuffer);
  1827.         }
  1828.     }
  1829.     }
  1830.     if (localInBuffer != (Address)NIL) {
  1831.     free(localInBuffer);
  1832.     }
  1833.     if (localOutBuffer != (Address)NIL) {
  1834.     free(localOutBuffer);
  1835.     }
  1836.     return(status);
  1837. }
  1838.  
  1839.  
  1840. /*
  1841.  *----------------------------------------------------------------------
  1842.  *
  1843.  * Fs_CreatePipeStub --
  1844.  *
  1845.  *      This is the stub for the Fsio_CreatePipe system call.  This routine sets
  1846.  *      up stream IDs for the two Fs_Stream objects returned by (the internal)
  1847.  *      Fsio_CreatePipe: one for reading the pipe and one for writing to it.
  1848.  *
  1849.  * Results:
  1850.  *    A retrun status or SUCCESS if successful.
  1851.  *
  1852.  * Side effects:
  1853.  *    The two arguments are out parameters and get filled in with a
  1854.  *    stream id.  Also, opening a pipe sets up state until both ends are 
  1855.  *    closed with Fs_Close system calls.
  1856.  *
  1857.  *----------------------------------------------------------------------
  1858.  */
  1859. ReturnStatus
  1860. Fs_CreatePipeStub(inStreamIDPtr, outStreamIDPtr)
  1861.     int *inStreamIDPtr;        /* Handle that the user can use to read the
  1862.                  * pipe. */
  1863.     int *outStreamIDPtr;    /* Handle that the user can use to write the
  1864.                  * pipe. */
  1865. {
  1866.     register ReturnStatus    status;
  1867.     Fs_Stream            *inStreamPtr;
  1868.     int                 inStreamID;
  1869.     Fs_Stream            *outStreamPtr;
  1870.     int                outStreamID;
  1871.  
  1872.     /*
  1873.      * Call the internal routine to create the pipe.
  1874.      */
  1875.     status = Fsio_CreatePipe(&inStreamPtr, &outStreamPtr);
  1876.     if (status != SUCCESS) {
  1877.     return(status);
  1878.     }
  1879.     inStreamPtr->flags |= FS_USER;
  1880.     outStreamPtr->flags |= FS_USER;
  1881.  
  1882.     /*
  1883.      * Get stream ids for the two streams.
  1884.      */
  1885.  
  1886.     status = Fs_GetStreamID(inStreamPtr, &inStreamID);
  1887.     if (status != SUCCESS) {
  1888.     (void) Fs_Close(inStreamPtr);
  1889.     (void) Fs_Close(outStreamPtr);
  1890.     return(status);
  1891.     }
  1892.     status = Fs_GetStreamID(outStreamPtr, &outStreamID);
  1893.     if (status != SUCCESS) {
  1894.     Fs_ClearStreamID(inStreamID, (Proc_ControlBlock *)NIL);
  1895.     (void) Fs_Close(inStreamPtr);
  1896.     (void) Fs_Close(outStreamPtr);
  1897.     return(status);
  1898.     }
  1899.  
  1900.     /*
  1901.      * Copy out the stream ids to the user.
  1902.      */
  1903.  
  1904.     if (Vm_CopyOut(sizeof(int), (Address) &inStreamID, 
  1905.            (Address) inStreamIDPtr) == SUCCESS &&
  1906.     Vm_CopyOut(sizeof(int), (Address) &outStreamID, 
  1907.            (Address) outStreamIDPtr) == SUCCESS) {
  1908.     return(SUCCESS);
  1909.     }
  1910.  
  1911.     /*
  1912.      * If couldn't copy out then clean up state and return an error.
  1913.      */
  1914.  
  1915.     Fs_ClearStreamID(inStreamID, (Proc_ControlBlock *)NIL);
  1916.     Fs_ClearStreamID(outStreamID, (Proc_ControlBlock *)NIL);
  1917.     (void) Fs_Close(inStreamPtr);
  1918.     (void) Fs_Close(outStreamPtr);
  1919.  
  1920.     return(SYS_ARG_NOACCESS);
  1921. }
  1922.  
  1923.